package storage;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;

import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import data.Reference;

public class RuleGroup extends JPanel implements ActionListener{
	public static final int ENABLE_FIELDS = 0;
	public static final int DISABLE_FIELDS = 1;
	
	private static final long serialVersionUID = 1L;
	public JLabel groupLabel;
	public JComboBox groupCombo;
	public JLabel markIfLabel;
	public JComboBox subjectFieldCombo;
	public JLabel isLabel;
	public JTextField valueText;
	public JComboBox equalityCombo;
	public JComboBox targetFieldCombo;
	public JLabel connectorLabel;
	public JComboBox connectorCombo;
	public JLabel subjectFieldLabel;
	public JLabel valueLabel;
	public JLabel equalityLabel;
	public JLabel targetFieldLabel;
	public GridBagConstraints gbc;
	private ArrayList<RuleGroup> listenerList;
	
	public RuleGroup(){
		super();
		listenerList = new ArrayList<RuleGroup>();
		gbc = new GridBagConstraints();
		groupLabel  = new JLabel("Group No");
		groupCombo = new JComboBox(Reference.groupNoList.toArray());
		groupCombo.setPreferredSize(new Dimension(50,25));
		groupCombo.setMinimumSize(new Dimension(100,25));
		markIfLabel = new JLabel("Mark If");
				
		updateRuleGroupFields();
		subjectFieldCombo.addItem("TODAY");
		subjectFieldCombo.setPreferredSize(new Dimension(100,25));
		subjectFieldCombo.setMinimumSize(new Dimension(100,25));
		isLabel = new JLabel("is");
		valueText = new JTextField();
		valueText.setPreferredSize(new Dimension(100,25));
		valueText.setMinimumSize(new Dimension(100,25));
		equalityCombo = new JComboBox(Reference.equalityList.toArray());
		equalityCombo.setPreferredSize(new Dimension(100,25));
		equalityCombo.setMinimumSize(new Dimension(100,25));
		
		targetFieldCombo.addItem("TODAY");
		targetFieldCombo.setPreferredSize(new Dimension(100,25));
		targetFieldCombo.setMinimumSize(new Dimension(100,25));
		connectorLabel = new JLabel("Connector");
		connectorCombo = new JComboBox(Reference.connectorList.toArray());
		connectorCombo.setPreferredSize(new Dimension(100,25));
		connectorCombo.setMinimumSize(new Dimension(100,25));
		subjectFieldLabel = new JLabel("Subject Field");
		valueLabel = new JLabel("Value");
		equalityLabel = new JLabel("Equality");
		targetFieldLabel = new JLabel("Target Field");
		
		this.setLayout(new GridBagLayout());

		ItemListener connectorListener = new ItemListener(){
			@Override
			public void itemStateChanged(ItemEvent arg0) {
				if(!(connectorCombo.getSelectedItem()==null||connectorCombo.getSelectedItem().equals(""))){
					//something has been selected, active next rule
					fireActionEvent(RuleGroup.ENABLE_FIELDS);
				}else{
					fireActionEvent(RuleGroup.DISABLE_FIELDS);
				}
			}
		};
		connectorCombo.addItemListener(connectorListener);
		
		addPropertyChangedListeners();
		DocumentListener valueListener = new DocumentListener(){
			
				@Override
				public void changedUpdate(DocumentEvent evt) {
					if(subjectFieldCombo.getSelectedItem()!=null){
						if(valueText.getText().toUpperCase().equals("NULL")||valueText.getText().toUpperCase().equals("NOT NULL")){
							equalityCombo.setEnabled(false);
							equalityCombo.setSelectedIndex(-1);
							targetFieldCombo.setEnabled(false);
							targetFieldCombo.setSelectedIndex(-1);
							//If field is a number, change label to value
							valueLabel.setText("Value");
						}else if(FieldInfo.getFieldType((String)subjectFieldCombo.getSelectedItem()).equals("NUMBER")){
							equalityCombo.setEnabled(false);
							targetFieldCombo.setEnabled(false);
							targetFieldCombo.setSelectedIndex(-1);
							equalityCombo.setSelectedIndex(-1);
							//If field is a number, change label to # of days
							valueLabel.setText("Value");
						}else if(!FieldInfo.getFieldType((String)subjectFieldCombo.getSelectedItem()).equals("STRING")){
							equalityCombo.setEnabled(true);
							targetFieldCombo.setEnabled(true);
							//If field is a number, change label to # of days
							valueLabel.setText("# of DAYS");
						}
					}
				}
	
				@Override
				public void insertUpdate(DocumentEvent arg0) {
					if(subjectFieldCombo.getSelectedItem()!=null){
						if(valueText.getText().toUpperCase().equals("NULL")||valueText.getText().toUpperCase().equals("NOT NULL")){
							equalityCombo.setEnabled(false);
							equalityCombo.setSelectedIndex(-1);
							targetFieldCombo.setEnabled(false);
							targetFieldCombo.setSelectedIndex(-1);
							//If field is a number, change label to value
							valueLabel.setText("Value");
						}else if(FieldInfo.getFieldType((String)subjectFieldCombo.getSelectedItem()).equals("NUMBER")){
							equalityCombo.setEnabled(false);
							targetFieldCombo.setEnabled(false);
							targetFieldCombo.setSelectedIndex(-1);
							equalityCombo.setSelectedIndex(-1);
							//If field is a number, change label to # of days
							valueLabel.setText("Value");
						}else if(!FieldInfo.getFieldType((String)subjectFieldCombo.getSelectedItem()).equals("STRING")){
							equalityCombo.setEnabled(true);
							targetFieldCombo.setEnabled(true);
							//If field is a number, change label to # of days
							valueLabel.setText("# of DAYS");
						}
					}
				}
	
				@Override
				public void removeUpdate(DocumentEvent arg0) {
					if(subjectFieldCombo.getSelectedItem()!=null){
						if(valueText.getText().toUpperCase().equals("NULL")||valueText.getText().toUpperCase().equals("NOT NULL")){
							equalityCombo.setEnabled(false);
							equalityCombo.setSelectedIndex(-1);
							targetFieldCombo.setEnabled(false);
							targetFieldCombo.setSelectedIndex(-1);
							//If field is a number, change label to value
							valueLabel.setText("Value");
						}else if(FieldInfo.getFieldType((String)subjectFieldCombo.getSelectedItem()).equals("NUMBER")){
							equalityCombo.setEnabled(false);
							targetFieldCombo.setEnabled(false);
							targetFieldCombo.setSelectedIndex(-1);
							equalityCombo.setSelectedIndex(-1);
							//If field is a number, change label to # of days
							valueLabel.setText("Value");
						}else if(!FieldInfo.getFieldType((String)subjectFieldCombo.getSelectedItem()).equals("STRING")){
							equalityCombo.setEnabled(true);
							targetFieldCombo.setEnabled(true);
							//If field is a number, change label to # of days
							valueLabel.setText("# of DAYS");
						}
					}
				}
		};
		valueText.getDocument().addDocumentListener(valueListener);
		
		FocusListener valueFocusListener = new FocusListener(){
			@Override
			public void focusGained(FocusEvent arg0) {
			}

			@Override
			public void focusLost(FocusEvent arg0) {
				// On losing focus we want to check if the entered value is correct for the type
				// of field specified
				if(valueText.getText()!=null&&!valueText.getText().equals("")){
					 //field has something
					if((FieldInfo.getFieldType((String)subjectFieldCombo.getSelectedItem()).equals("DATE")||
							FieldInfo.getFieldType((String)subjectFieldCombo.getSelectedItem()).equals("NUMBER"))&&
							!valueText.getText().toUpperCase().equals("NULL")&&
							!valueText.getText().toUpperCase().equals("NOT NULL")){
						//value has to be an integer
						try{
							Integer.parseInt(valueText.getText());
						}catch(NumberFormatException e){
							JOptionPane.showMessageDialog(null, (String)subjectFieldCombo.getSelectedItem() + " must have a integer value!");
							valueText.setText("");
							valueText.requestFocus();
						}
					}else if(valueText.getText().toUpperCase().equals("NULL")&&
							valueText.getText().toUpperCase().equals("NOT NULL")){
						if(((String)subjectFieldCombo.getSelectedItem()).equals("TODAY")){
							JOptionPane.showMessageDialog(null, "\"TODAY\" cannot have a NULL or NOT NULL value");
						}
					}
				}
			}
		};
		valueText.addFocusListener(valueFocusListener);
		
		ItemListener subjectFieldListener = new ItemListener(){
			@Override
			public void itemStateChanged(ItemEvent arg0) {
				String name = (String)subjectFieldCombo.getSelectedItem();
				if(name!=null && name!=""){
					valueText.setEnabled(true);
					String type = FieldInfo.getFieldType(name);
					if(type.equals("STRING") || type.equals("NUMBER")){
						isLabel.setText("==");
						valueLabel.setText("Value");
						equalityCombo.setEnabled(false);
						equalityCombo.setSelectedIndex(-1);
						targetFieldCombo.setEnabled(false);
						targetFieldCombo.setSelectedIndex(-1);
					}else if(type.equals("DATE")&&!valueText.getText().toUpperCase().equals("NULL")){
						valueLabel.setText("# of DAYS");
						equalityCombo.setEnabled(true);
						targetFieldCombo.setEnabled(true);
						isLabel.setText("is");
					}
				}else{
					valueText.setEnabled(false);
				}
			}
		};
		subjectFieldCombo.addItemListener(subjectFieldListener);
		
		gbc.insets.top = 4;
		gbc.insets.bottom = 4;
		gbc.insets.left = 4;
		gbc.insets.right = 4;
		
		gbc.gridwidth =1;
		gbc.gridheight =1;
		
		gbc.gridx = 0;
		gbc.gridy = 0;
		this.add(groupLabel,gbc);

		gbc.gridx = 1;
		gbc.gridy = 0;
		this.add(groupCombo,gbc);
		
		gbc.gridx = 2;
		gbc.gridy = 0;
		this.add(markIfLabel,gbc);
		
		gbc.gridx = 3;
		gbc.gridy = 0;
		this.add(subjectFieldCombo,gbc);
		
		gbc.gridx  = 4;
		gbc.gridy = 0;
		this.add(isLabel,gbc);
		
		gbc.gridx = 5;
		gbc.gridy = 0;
		this.add(valueText,gbc);
		
		gbc.gridx = 6;
		gbc.gridy = 0;
		this.add(equalityCombo,gbc);
		
		gbc.gridx = 7;
		gbc.gridy = 0;
		this.add(targetFieldCombo,gbc);
		
		gbc.gridx = 0;
		gbc.gridy = 1;
		this.add(connectorLabel,gbc);
		
		gbc.gridx = 1;
		gbc.gridy = 1;
		this.add(connectorCombo,gbc);
		
		gbc.gridx = 3;
		gbc.gridy = 1;
		this.add(subjectFieldLabel,gbc);
		
		gbc.gridx = 5;
		gbc.gridy = 1;
		this.add(valueLabel,gbc);
		
		gbc.gridx = 6;
		gbc.gridy = 1;
		this.add(equalityLabel,gbc);
		
		gbc.gridx = 7;
		gbc.gridy = 1;
		this.add(targetFieldLabel,gbc);
	}
	/**
	 * Property changed listeners ties labels to their respective fields for easier enabling/disabling
	 */
	private void addPropertyChangedListeners() {
		PropertyChangeListener connectorPropertyListener = new PropertyChangeListener(){
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				connectorLabel.setEnabled(connectorCombo.isEnabled());			
			}
		};
		connectorCombo.addPropertyChangeListener(connectorPropertyListener);
		PropertyChangeListener groupPropertyListener = new PropertyChangeListener(){
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				groupLabel.setEnabled(groupCombo.isEnabled());			
			}
		};
		groupCombo.addPropertyChangeListener(groupPropertyListener);
		PropertyChangeListener subjectFieldPropertyListener = new PropertyChangeListener(){
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				subjectFieldLabel.setEnabled(subjectFieldCombo.isEnabled());			
			}
		};
		subjectFieldCombo.addPropertyChangeListener(subjectFieldPropertyListener);
		PropertyChangeListener valuePropertyListener = new PropertyChangeListener(){
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				valueLabel.setEnabled(valueText.isEnabled());			
			}
		};
		valueText.addPropertyChangeListener(valuePropertyListener);
		PropertyChangeListener equalityPropertyListener = new PropertyChangeListener(){
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				equalityLabel.setEnabled(equalityCombo.isEnabled());			
			}
		};
		equalityCombo.addPropertyChangeListener(equalityPropertyListener);
		PropertyChangeListener targetFieldPropertyListener = new PropertyChangeListener(){
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				targetFieldLabel.setEnabled(targetFieldCombo.isEnabled());			
			}
		};
		targetFieldCombo.addPropertyChangeListener(targetFieldPropertyListener);
	}
	public void clear(){
		groupCombo.setSelectedIndex(0);
		subjectFieldCombo.setSelectedIndex(-1);
		connectorCombo.setSelectedIndex(-1); //test
		isLabel.setText("is");
		valueText.setText("");
		equalityCombo.setSelectedIndex(-1);
		targetFieldCombo.setSelectedIndex(-1);
	}
	public void setEnabled(boolean enabled){
		if((Integer)groupCombo.getSelectedItem()!=1){
			groupCombo.removeAllItems();
			for(int i=0;i<Reference.groupNoList.toArray().length;i++){
				groupCombo.addItem(Reference.groupNoList.toArray()[i]);
			}
		}
		if(enabled){
			//clear();
			setEnabled(false);
			groupCombo.setEnabled(true);
			subjectFieldCombo.setEnabled(true);
			connectorCombo.setEnabled(true);
			//labels
			subjectFieldLabel.setEnabled(true);
			connectorLabel.setEnabled(true);
			groupLabel.setEnabled(true);
			markIfLabel.setEnabled(true);
			isLabel.setEnabled(true);
		}else{
			clear();
			groupCombo.setEnabled(false);
			subjectFieldCombo.setEnabled(false);
			valueText.setEnabled(false);
			equalityCombo.setEnabled(false);
			targetFieldCombo.setEnabled(false);
			connectorCombo.setEnabled(false);
			
			//labels
			subjectFieldLabel.setEnabled(false);
			valueLabel.setEnabled(false);
			equalityLabel.setEnabled(false);
			targetFieldLabel.setEnabled(false);
			connectorLabel.setEnabled(false);
			groupLabel.setEnabled(false);
			markIfLabel.setEnabled(false);
			isLabel.setEnabled(false);
		}
		if(listenerList.size()==0){
			connectorCombo.removeAllItems();
			connectorCombo.setEnabled(false);
			connectorLabel.setEnabled(false);
		}
	}
	public void addActionListener(RuleGroup ruleGroup){
		if(!listenerList.contains(ruleGroup))
			listenerList.add(ruleGroup);
	}
	public void fireActionEvent(int id){
		for(int i=0;i<listenerList.size();i++){
			ActionEvent e = new ActionEvent(this, id, "");
			listenerList.get(i).actionPerformed(e);
		}
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		//Enable or Disable
		if(e.getID()==RuleGroup.ENABLE_FIELDS){
			setEnabled(true);
		}else{
			setEnabled(false);
		}
	}
	public void updateRuleGroupFields(){
		if(subjectFieldCombo==null)
			subjectFieldCombo = new JComboBox(FieldInfo.getFieldNames());
		else{
			subjectFieldCombo.removeAllItems();
			for(int i=0;i<FieldInfo.getFieldNames().length;i++){
				subjectFieldCombo.addItem(FieldInfo.getFieldNames()[i]);
			}
			subjectFieldCombo.addItem("TODAY");
		}
		if(targetFieldCombo==null)
			targetFieldCombo = new JComboBox(FieldInfo.getNumericalFieldNames());
		else{
			targetFieldCombo.removeAllItems();
			for(int i=0;i<FieldInfo.getNumericalFieldNames().length;i++){
				targetFieldCombo.addItem(FieldInfo.getNumericalFieldNames()[i]);
			}
			targetFieldCombo.addItem("TODAY");
		}
	}
}
